#include <stdio.h>
#include <stdlib.h>
#include <malloc.h>
#include <string.h>
#include <string>
#include <time.h>
#include "../common.h"
extern "C" {
#include "../yy.h"
}
#include "../sizer.h"
#include "../pcoder.h"
#include "../display.h"
#include "pic16e.h"
#include "pic16e_asm.h"
#include "pic16e_inst.h"

void PIC16E :: passarg(Item *ip0, Item *ip1, Item *ip2)
{
	char passarg_asm[64];

	switch (ip1->type) {
		case ID_ITEM: {
			Dnode* dp = serachVarable(ip1->vname);
			if (ip1->attr->isStatic){
			sprintf(passarg_asm,"\tlui \ta5,%%hi(%s)\n"
				"\tlw  \ta5, %%lo(%s)(a5)\n"
				"\tmv  \ta%s, a5\n"
				,ip1->vname,ip1->vname,ip0->val.s); 
			}else { sprintf(passarg_asm,"\tlw  \ta%s, %s\n",ip0->val.s,dp->memStr); }
		}
		break;	
		case CON_ITEM: {
			sprintf(passarg_asm,"\tli  \ta%s, %d\n",ip0->val.s, ip1->val.i); 
		}
		break;
		case TEMP_ITEM:{
			sprintf(passarg_asm,"\tmv  \ta%s, t%d\n",ip0->val.s, ip1->val.i); 
		}
		break;
		case IMMD_ITEM: {
			Dnode* dp = serachVarable(ip1->vname);
			if (ip1->bias){
				int bias = std::stoi(dp->memStr) - ip1->bias;
				sprintf(passarg_asm,"\taddi  \ta%s, s0, %d\n",ip0->val.s, bias); 
			}else {
				sprintf(passarg_asm,"\taddi  \ta%s, s0, %s\n",ip0->val.s,dp->memStr); 
			}
		}
		case ACC_ITEM:{
			
		}
		break;
		default:
		break;
	}
	
	ASM_OUTP(passarg_asm);

}



void PIC16E :: sub(Item *ip0, Item *ip1, Item *ip2)
{
	parseAddItem(ip1, 2, ip1->attr->offset, 1);
	parseAddItem(ip2, 3, ip2->attr->offset, 1);
	parseAddItem(ip0, 1, ip0->attr->offset, 1);
}
// strict   2-> 3 -> 1
void PIC16E :: parseAddItem(Item *ip, int idx, int offset, int sub){
	char* code;
	if (sub){ code = (char*)"sub ";	}
	else { code = (char*)"add "; }
	switch (ip->type) {
		case CON_ITEM: {
			if (idx == 2){
				ASM_CODE(_LI,_R_A4,ip->val.i);
			}else if (idx == 3){
				ASM_CODE(_LI,_R_A5,ip->val.i);
			}
		}break;
		case IMMD_ITEM:	{			
				if (idx == 2){
					ASM_CODE(_LI, _R_A4, 0);
				}else if (idx == 3){
					ASM_CODE(_LI, _R_A5, 0);
				}else if (idx == 1){
					errPrint("no immd_item at add 1");
				}
		}break;
		case ID_ITEM:{
			if (ip->attr->isStatic == -1){
				char buf[64];
				if (idx == 2){
						sprintf(buf,"\tlui \ta6,%%hi(%s)\n\tlw  \ta4,%%lo(%s)(a6)\n", ip->vname, ip->vname); 
						ASM_OUTP(buf);
				}else if (idx == 3){
						sprintf(buf,"\tlui \ta6,%%hi(%s)\n\tlw  \ta5,%%lo(%s)(a6)\n", ip->vname, ip->vname); 
						ASM_OUTP(buf);
				}else if (idx == 1){
					/**
							lui     a5,%hi(a)
							sw      a4,%lo(a)(a5)
					 */
					ASM_CODE(code, _R_A4, _R_A4, _R_A5);
					sprintf(buf,"\tlui \ta5,%%hi(%s)\n\tsw  \ta4,%%lo(%s)(a5)\n", ip->vname, ip->vname); 
					ASM_OUTP(buf);
				}
				break;
			}
			
			if (curFunc != NULL){
				if (ip->fname != curFunc->name){
					errPrint("function not matched error");
				}
				Dnode* dp = serachVarable(ip->vname);	
				char buf[128];
				if (idx == 2){
					if (dp->attr->dimVect){
						char buf[128];
						int _offset = std::atoi(dp->memStr) + offset;
						sprintf(buf,"\tlw  \ta4, %d(s0)\n",_offset); ASM_OUTP(buf);
					}else {
						ASM_CODE(_LW,_R_A4, dp->memStr);
					}
				}else if (idx == 3){
					if (dp->attr->dimVect){
						char buf[128];
						int _offset = std::atoi(dp->memStr) + offset;
						sprintf(buf,"\tlw  \ta5, %d(s0)\n",_offset); ASM_OUTP(buf);
					}else {
						ASM_CODE(_LW,_R_A5, dp->memStr);
					}
				}else if (idx == 1){
					ASM_CODE(code, _R_A5, _R_A4, _R_A5);
					ASM_CODE(_SW,_R_A5, dp->memStr);
					ASM_CODE(_LI,_R_A5, 0);
				}
			}
		}break;
		case ACC_ITEM:{
			ASM_CODE(_ADD, _R_A0, _R_A4, _R_A5);
		}break;
		case INDIR_ITEM:{
			if (curFunc != NULL){
				if (ip->fname != curFunc->name){
					errPrint("function not matched error");
				}
				Dnode* dp = serachVarable(ip->vname);	
				char buf[128];
				if (idx == 2){
					if (dp->attr->dimVect){
						char buf[128];
						int _offset = std::atoi(dp->memStr) + offset;
						sprintf(buf,"\tlw  \ta4, %d(s0)\n",_offset); ASM_OUTP(buf);
					}else {
						ASM_CODE(_LW,_R_A4, dp->memStr);
					}
				}else if (idx == 3){
					if (dp->attr->dimVect){
						char buf[128];
						int _offset = std::atoi(dp->memStr) + offset;
						sprintf(buf,"\tlw  \ta5, %d(s0)\n",_offset); ASM_OUTP(buf);
					}else {
						ASM_CODE(_LW,_R_A5, dp->memStr);
					}
				}else if (idx == 1){
					ASM_CODE(code, _R_A5, _R_A4, _R_A5);
					ASM_CODE(_SW,_R_A5, dp->memStr);
					ASM_CODE(_LI,_R_A5, 0);
				}
			}
		}
		case TEMP_ITEM:{
			if (curFunc != NULL){
				if (idx == 1){
					char buf[64]; sprintf(buf,"\t%s\tt%d, a4, a5\n",code, ip->memRgx); ASM_OUTP(buf);
				} else if (idx == 2) {
					char buf[64]; sprintf(buf,"\tmv  \ta4, t%d\n", ip->memRgx); ASM_OUTP(buf);
				} else if (idx == 3){
					char buf[64]; sprintf(buf,"\tmv  \ta5, t%d\n", ip->memRgx); ASM_OUTP(buf);
				}
			}
		}break;
		default:
		break;
			//errPrint("gen add isa error!");
	}
}

/**
 *  1. int c = a + b
	2. int c = 1 + b
	3. int c = b + 1
	4. int c = 1 + 1
	5. return a + b
	ip0  type 
	1. ID_ITEM 1 - 4
	2. ACC_ITEM 5 - 8
	ip1 type
	1. ID_ITEM
	2. CON_ITEM
 */	
void PIC16E :: add(Item *ip0, Item *ip1, Item *ip2)
{
	parseAddItem(ip1, 2, ip1->attr->offset, 0);
	parseAddItem(ip2, 3, ip2->attr->offset, 0);
	parseAddItem(ip0, 1, ip0->attr->offset, 0);
}

